package com.ruige.account.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruige.account.entity.NameValue;
import com.ruige.account.mapper.AccountLogMapper;
import com.ruige.account.mapper.AccountMapper;
import com.ruige.account.pojo.Account;
import com.ruige.account.pojo.AccountLog;
import com.ruige.account.service.IAccountLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author huangrui
 * @since 2020-05-25
 */
@Service
public class AccountLogServiceImpl extends ServiceImpl<AccountLogMapper, AccountLog> implements IAccountLogService {
    public static final Map<Integer, String> CHANGE_TYPE = new HashMap<Integer, String>() {{
        put(4, "餐饮");
        put(5, "通讯");
        put(6, "交通");
        put(7, "购物");
        put(8, "住房");
        put(9, "娱乐");
        put(10, "医疗");
        put(11, "教育");
        put(12, "红包");
        put(13, "旅行");
        put(14, "投资");
        put(15, "还款");
        put(16, "宠物");
        put(17, "还债");
        put(18, "其他");
    }};


    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountLogMapper accountLogMapper;

    @Override
    public List<NameValue> getRatioYearChartData(Integer userId, LocalDate year) {
        List<NameValue> result = new ArrayList<>();
        LocalDate start = year.with(TemporalAdjusters.firstDayOfYear());
        LocalDate end = year.with(TemporalAdjusters.lastDayOfYear());
        QueryWrapper<AccountLog> wrapper = new QueryWrapper<>();
        wrapper.select("SUM(change_money) as change_money , change_type ")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .ge("create_time", start)
                .le("create_time", end)
                .groupBy("change_type");
        List<AccountLog> accountLogs = accountLogMapper.selectList(wrapper);
        System.out.println("accountLogs = " + accountLogs);
        for (AccountLog accountLog : accountLogs) {
            NameValue nameValue = new NameValue();
            nameValue.setName(CHANGE_TYPE.get(accountLog.getChangeType()));
            nameValue.setValue(accountLog.getChangeMoney());
            result.add(nameValue);
        }
        return result;
    }

    @Override
    public List<NameValue> getRatioChartData(Integer userId, LocalDate localDate) {
        List<NameValue> result = new ArrayList<>();
        LocalDate start = localDate.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate end = localDate.with(TemporalAdjusters.lastDayOfMonth());
        QueryWrapper<AccountLog> wrapper = new QueryWrapper<>();
        wrapper.select("SUM(change_money) as change_money , change_type ")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .ge("create_time", start)
                .le("create_time", end)
                .groupBy("change_type");
        List<AccountLog> accountLogs = accountLogMapper.selectList(wrapper);
        System.out.println("accountLogs = " + accountLogs);
        for (AccountLog accountLog : accountLogs) {
            NameValue nameValue = new NameValue();
            nameValue.setName(CHANGE_TYPE.get(accountLog.getChangeType()));
            nameValue.setValue(accountLog.getChangeMoney());
            result.add(nameValue);
        }
        return result;
    }

    @Override
    public Map<String, List> getCurveChartData(Integer userId, LocalDate localDate) {
        Map<String, List> resultMap = new LinkedHashMap<>();
        //获取本月有多少天
        int lengthOfMonth = localDate.lengthOfMonth();
        //创建本月头一天日期
        LocalDate startOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate endOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("startOfMonth = " + startOfMonth);
        System.out.println("endOfMonth = " + endOfMonth);
        QueryWrapper<AccountLog> wrapper = new QueryWrapper<>();
        wrapper.select("SUM(change_money) as change_money , day ")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .ge("create_time", startOfMonth)
                .le("create_time", endOfMonth)
                .groupBy("day");
        List<AccountLog> accountLogs = accountLogMapper.selectList(wrapper);

        List<String> curveData = new ArrayList();
        List<BigDecimal> curveDataSeries = new ArrayList();

        String date;
        LocalDate time;
        BigDecimal data = BigDecimal.valueOf(0);
        for (int i = 0; i < lengthOfMonth; i++) {
            date = String.valueOf(i + 1);
            curveData.add(date);
            time = startOfMonth.plusDays(i);
            for (AccountLog accountLog : accountLogs) {
                if (accountLog.getDay() == time.getDayOfMonth()) {
                    data = accountLog.getChangeMoney().add(data);
                }
            }
            if (time.getDayOfMonth() <= localDate.getDayOfMonth() && data.intValue() != 0) {
                curveDataSeries.add(data);
            } else {
                curveDataSeries.add(null);
            }
        }
        resultMap.put("curveData", curveData);
        resultMap.put("curveDataSeries", curveDataSeries);
        System.out.println("accountLogs = " + accountLogs);
        System.out.println("resultMap = " + resultMap);
        return resultMap;
    }

    @Override
    public Map<String, List> getWeekChartData(Integer userId) {
        Map<String, List> resultMap = new LinkedHashMap<>();

//        SELECT SUM(change_money) change_money,day
//        FROM blog_account_log
//        WHERE user_id=1
//        AND create_time AND create_time>='2020-06-08' AND create_time<='2020-06-14'
//        GROUP BY day
        LocalDate today = LocalDate.now();
        LocalDate weekAgo = today.plusDays(-6);
        QueryWrapper<AccountLog> wrapper = new QueryWrapper<>();
        wrapper.select("SUM(change_money) as change_money , day ")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .ge("create_time", weekAgo)
                .le("create_time", today)
                .groupBy("day");
        List<AccountLog> accountLogs = accountLogMapper.selectList(wrapper);


        List<String> weekChartData = new ArrayList();
        List<BigDecimal> weekChartSeries = new ArrayList();
        String date;
        LocalDate time;
        BigDecimal data = null;
        for (int i = 7; i > 0; i--) {
            time = today.plusDays(-i + 1);
            date = time.getMonthValue() + "." + time.getDayOfMonth();
            weekChartData.add(date);
            data = BigDecimal.valueOf(0);
            for (AccountLog accountLog : accountLogs) {
                if (accountLog.getDay() == time.getDayOfMonth()) {
                    data = accountLog.getChangeMoney();
                }
            }
            weekChartSeries.add(data);
        }
        resultMap.put("weekChartData", weekChartData);
        resultMap.put("weekChartSeries", weekChartSeries);
        return resultMap;
    }

    @Override
    public Integer deleteById(Integer id) {
        return accountLogMapper.deleteById(id);
    }

    @Override
    public IPage<AccountLog> findLogByPage(Long page, Long rows, Integer userId) {
        IPage<AccountLog> iPage = accountLogMapper.selectPage(new Page<>(page, rows),
                Wrappers.<AccountLog>lambdaQuery().eq(AccountLog::getUserId, userId).orderByDesc(AccountLog::getCreateTime));
        return iPage;
    }

    @Override
    public Map<String, BigDecimal> baseInfo(Integer userId) {
        //创建结果map
        Map<String, BigDecimal> result = new HashMap<>();

        LocalDate today = LocalDate.now();

        //查询余额
        Account account = accountMapper.selectByUserId(userId);
        if (account == null) {
            result.put("account", BigDecimal.valueOf(0));
        } else {
            result.put("account", account.getAccount());
        }

        //查询当日消费
//        SELECT sum(change_money) as change_money
//        FROM blog_account_log
//        WHERE user_id=1 AND change_type>3
//        AND `year`=2020 AND `month`=6 AND `day`=12
        QueryWrapper<AccountLog> todayWrapper = new QueryWrapper<>();
        todayWrapper.select("sum(change_money) as change_money")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .eq("year", today.getYear())
                .eq("month", today.getMonthValue())
                .eq("day", today.getDayOfMonth());
        AccountLog todayUse = accountLogMapper.selectOne(todayWrapper);
        if (todayUse == null) {
            result.put("todayUse", BigDecimal.valueOf(0));
        } else {
            result.put("todayUse", todayUse.getChangeMoney());
        }

        //查询本周消费
//        SELECT sum(change_money) as change_money
//        FROM blog_account_log WHERE user_id=1 AND change_type>3
//        AND create_time>='2020-06-06' AND create_time<='2020-06-12'
        LocalDate weekAgo = today.plusDays(-6);
        QueryWrapper<AccountLog> weekWrapper = new QueryWrapper<>();
        weekWrapper.select("sum(change_money) as change_money")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .ge("create_time", weekAgo)
                .le("create_time", today);
        AccountLog weekUse = accountLogMapper.selectOne(weekWrapper);
        if (weekUse == null) {
            result.put("weekUse", BigDecimal.valueOf(0));
        } else {
            result.put("weekUse", weekUse.getChangeMoney());
        }

        //查询本月消费
//        SELECT sum(change_money) as change_money
//        FROM blog_account_log
//        WHERE change_type > 3 AND user_id = 1
//        AND year = 2020 AND month = 6 AND day >= 1 AND day <= 30;
        QueryWrapper<AccountLog> monthWrapper = new QueryWrapper<>();
        monthWrapper.select("sum(change_money) as change_money")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .eq("year", today.getYear())
                .eq("month", today.getMonthValue())
                .ge("day", 1)
                .le("day", today.lengthOfMonth());
        AccountLog monthUse = accountLogMapper.selectOne(monthWrapper);
        if (monthUse == null) {
            result.put("monthUse", BigDecimal.valueOf(0));
            result.put("monthAvgUse", BigDecimal.valueOf(0));
        } else {
            result.put("monthUse", monthUse.getChangeMoney());
            BigDecimal monthAvgUse = monthUse.getChangeMoney().divide(BigDecimal.valueOf(today.getDayOfMonth()), 2, BigDecimal.ROUND_HALF_UP);
            //查询月均消费为计算所得,当月消费除以当天日期
            System.out.println("monthAvgUse = " + monthAvgUse);
            result.put("monthAvgUse", monthAvgUse);
        }

        //查询本年消费
        QueryWrapper<AccountLog> yearWrapper = new QueryWrapper<>();
        yearWrapper.select("sum(change_money) as change_money")
                .gt("change_type", 3)
                .eq("user_id", userId)
                .eq("year", today.getYear());
        AccountLog yearUse = accountLogMapper.selectOne(yearWrapper);
        if (yearUse == null) {
            result.put("yearUse", BigDecimal.valueOf(0));
        } else {
            result.put("yearUse", yearUse.getChangeMoney());
        }
        return result;
    }

    @Override
    @Transactional
    public void editLog(AccountLog accountLog) {


        AccountLog log = accountLogMapper.selectById(accountLog.getId());
        Account account = accountMapper.selectByUserId(accountLog.getUserId());
        if (log != null) {
            //查询到的记录减去要改为的记录
            BigDecimal change = log.getChangeMoney().subtract(accountLog.getChangeMoney());
            //无论大于小于0均使用add方法更新设置余额
            account.setAccount(account.getAccount().add(change));
            //更新记账日志
            accountLogMapper.updateById(accountLog);
            //更新余额
            accountMapper.updateById(account);
        }
    }

    @Override
    public List<AccountLog> findAll() {
        return accountLogMapper.selectList(new QueryWrapper<>());
    }

    @Override
    @Transactional
    public void change(AccountLog accountLog) {
        //设置参数
        accountLog.setChangeTime(LocalDateTime.now());
        accountLog.setYear(accountLog.getCreateTime().getYear());
        accountLog.setMonth(accountLog.getCreateTime().getMonthValue());
        accountLog.setDay(accountLog.getCreateTime().getDayOfMonth());
        //添加记账日志
        if (accountLog.getChangeType() > 3) {
            accountLog.setChangeTypeName("支出");
        } else {
            accountLog.setChangeTypeName("收入");
        }
        accountLogMapper.insert(accountLog);
        //先获取该user是否有账户信息
        Account kaAccount = accountMapper.selectByUserId(accountLog.getUserId());
        //若账户存在则直接进行操作
        if (kaAccount != null && kaAccount.getUserId() != null) {
            //大于2为支出,否则为收入
            if (accountLog.getChangeType() > 3) {
                //subtract方法计算余额
                kaAccount.setAccount(kaAccount.getAccount().subtract(accountLog.getChangeMoney()));
            } else {
                //小于3为收入,subtract方法计算减少余额
                kaAccount.setAccount(kaAccount.getAccount().add(accountLog.getChangeMoney()));
            }
            //更新余额
            accountMapper.updateById(kaAccount);
        } else {
            //没有账户信息则创建行用户并将余额添加到账户中
            Account account = new Account();
            account.setUserId(accountLog.getUserId());
            if (accountLog.getChangeType() > 3) {
                account.setAccount(BigDecimal.valueOf(0).subtract(accountLog.getChangeMoney()));
            } else {
                account.setAccount(accountLog.getChangeMoney());
            }
            accountMapper.insert(account);
        }

    }
}
